/**
 * @file telemetry_data.c
 * @brief 遥信数据模块实现
 * @details 本文件实现了104协议的遥信数据处理功能，包括单点信息、双点信息、
 *          带时标的单点信息、带时标的双点信息、故障事件信息等数据类型的
 *          序列化和反序列化操作。支持完整的数据转换和验证功能。
 * 
 * @author zyb
 * @date 2025-10-09
 * @version 1.0
 * 
 * @note 所有函数都遵循104协议规范，确保严格的数据处理
 * @warning 数据转换失败时应返回相应的错误码，便于上层处理
 * 
 * @see telemetry_data.h
 * @see protocol_types.h
 * @see buffer_utils.h
 * @see time_utils.h
 */

#include "telemetry_data.h"
#include "../../common/types/include/protocol_types.h"
#include "../../../../../common/utils/include/buffer_utils.h"
#include "../../common/utils/include/time_utils.h"
#include "../../common/error/include/error_codes.h"
#include "../../common/utils/include/validation_utils.h"
#include "../../../../../common/logs/include/logger.h"
#include <string.h>

// 定义模块名称
#define LOG_MODULE_NAME "TELEMETRY_DATA"

/* ==================== 单点信息处理函数实现 ==================== */

/**
 * @brief 单点信息转换为字节数组
 * @details 将单点信息结构转换为104协议规定的字节数组格式。
 *          按照协议规范进行数据序列化。
 * 
 * @param info 单点信息结构，不能为NULL
 * @param buffer 输出缓冲区，不能为NULL
 * @param buffer_size 缓冲区大小
 * @param actual_length 实际写入长度输出，不能为NULL
 * @return 协议错误码
 *         - PROTOCOL_SUCCESS: 转换成功
 *         - PROTOCOL_ERROR_NULL_POINTER: 空指针错误
 *         - PROTOCOL_ERROR_BUFFER_TOO_SMALL: 缓冲区太小
 *         - PROTOCOL_ERROR_ASDU_INVALID_ADDRESS: 地址无效
 * 
 * @note 按照104协议规范进行数据序列化
 * @warning 缓冲区大小必须足够容纳转换后的数据
 * 
 * @see bytes_to_single_point_info
 * @see validate_single_point_info
 * @see buffer_write_u32
 * @see buffer_write_u8
 */
protocol_error_t single_point_info_to_bytes(const single_point_info_t* info,
                                           u8* buffer, u32 buffer_size, u32* actual_length) {
    LOG_DEBUG(LOG_MODULE_NAME, "转换单点信息到字节数组: info=%p, buffer=%p, buffer_size=%u", 
              info, buffer, buffer_size);
    
    if (info == NULL || buffer == NULL || actual_length == NULL) {
        LOG_ERROR(LOG_MODULE_NAME, "空指针参数错误");
        return PROTOCOL_ERROR_NULL_POINTER;
    }
    
    /* 验证单点信息 */
    LOG_DEBUG(LOG_MODULE_NAME, "验证信息对象地址: %u", info->info_addr);
    if (!is_info_address_valid(info->info_addr)) {
        LOG_ERROR(LOG_MODULE_NAME, "无效的信息对象地址: %u", info->info_addr);
        return PROTOCOL_ERROR_ASDU_INVALID_ADDRESS;
    }
    LOG_DEBUG(LOG_MODULE_NAME, "信息对象地址验证通过");
    
    LOG_DEBUG(LOG_MODULE_NAME, "验证单点信息品质");
    if (!is_siq_valid(*(uint8_t*)&info->siq)) {
        LOG_ERROR(LOG_MODULE_NAME, "无效的单点信息品质");
        return PROTOCOL_ERROR_DATA_INVALID_VALUE;
    }
    LOG_DEBUG(LOG_MODULE_NAME, "单点信息品质验证通过");
    
    /* 检查缓冲区大小 */
    if (buffer_size < 4) { /* 地址(3字节) + SIQ(1字节) */
        LOG_ERROR(LOG_MODULE_NAME, "缓冲区太小: %u < 4", buffer_size);
        return PROTOCOL_ERROR_BUFFER_TOO_SMALL;
    }
    LOG_DEBUG(LOG_MODULE_NAME, "缓冲区大小检查通过: %u >= 4", buffer_size);
    
    /* 写入信息对象地址 */
    LOG_DEBUG(LOG_MODULE_NAME, "写入信息对象地址: %u", info->info_addr);
    buffer_write_u32(buffer, 0, info->info_addr, 0);
    
    /* 写入SIQ */
    LOG_DEBUG(LOG_MODULE_NAME, "写入SIQ: 0x%02X 到缓冲区[3]", *(u8*)&info->siq);
    memcpy(&buffer[3], &info->siq, sizeof(siq_t));
    
    *actual_length = 4;
    LOG_INFO(LOG_MODULE_NAME, "单点信息成功转换为字节数组，实际长度: %u", *actual_length);
    return PROTOCOL_SUCCESS;
}

/**
 * @brief 字节数组转换为单点信息
 * @details 将104协议规定的字节数组格式转换为单点信息结构。
 *          按照协议规范进行数据反序列化。
 * 
 * @param data 字节数组，不能为NULL
 * @param length 数据长度
 * @param info 单点信息结构输出，不能为NULL
 * @return 协议错误码
 *         - PROTOCOL_SUCCESS: 转换成功
 *         - PROTOCOL_ERROR_NULL_POINTER: 空指针错误
 *         - PROTOCOL_ERROR_BUFFER_TOO_SMALL: 数据长度不足
 *         - PROTOCOL_ERROR_ASDU_INVALID_ADDRESS: 地址无效
 * 
 * @note 按照104协议规范进行数据反序列化
 * @warning 数据长度必须足够容纳单点信息
 * 
 * @see single_point_info_to_bytes
 * @see validate_single_point_info
 * @see buffer_read_u32
 * @see buffer_read_u8
 */
protocol_error_t bytes_to_single_point_info(const u8* data, u32 length,
                                           single_point_info_t* info) {
    LOG_DEBUG(LOG_MODULE_NAME, "从字节数组转换单点信息: data=%p, length=%u, info=%p", 
              data, length, info);
    
    if (data == NULL || info == NULL) {
        LOG_ERROR(LOG_MODULE_NAME, "空指针参数错误");
        return PROTOCOL_ERROR_NULL_POINTER;
    }
    
    /* 检查数据长度 */
    if (length < 4) { /* 地址(3字节) + SIQ(1字节) */
        LOG_ERROR(LOG_MODULE_NAME, "数据长度太小: %u < 4", length);
        return PROTOCOL_ERROR_BUFFER_TOO_SMALL;
    }
    
    LOG_DEBUG(LOG_MODULE_NAME, "数据长度检查通过: %u >= 4", length);
    
    /* 读取信息对象地址 */
    LOG_DEBUG(LOG_MODULE_NAME, "读取信息对象地址从缓冲区[0-2]");
    info->info_addr = buffer_read_u32(data, 0, NULL, 0);
    
    /* 读取SIQ */
    LOG_DEBUG(LOG_MODULE_NAME, "读取SIQ从缓冲区[3]");
    memcpy(&info->siq, &data[3], sizeof(siq_t));
    
    LOG_DEBUG(LOG_MODULE_NAME, "读取完成: 地址=%u, SIQ=0x%02X", 
              info->info_addr, *(u8*)&info->siq);
    
    /* 验证转换后的数据 */
    LOG_DEBUG(LOG_MODULE_NAME, "验证转换后的数据");
    if (!is_info_address_valid(info->info_addr)) {
        LOG_ERROR(LOG_MODULE_NAME, "信息对象地址无效: %u", info->info_addr);
        return PROTOCOL_ERROR_ASDU_INVALID_ADDRESS;
    }
    
    if (!is_siq_valid(*(uint8_t*)&info->siq)) {
        LOG_ERROR(LOG_MODULE_NAME, "SIQ无效: 0x%02X", *(u8*)&info->siq);
        return PROTOCOL_ERROR_DATA_INVALID_VALUE;
    }
    
    LOG_INFO(LOG_MODULE_NAME, "单点信息转换成功: 地址=%u, SIQ=0x%02X", 
             info->info_addr, *(u8*)&info->siq);
    return PROTOCOL_SUCCESS;
}

/**
 * @brief 验证单点信息
 * @details 验证单点信息结构的完整性和有效性。
 *          检查地址和品质描述词的有效性。
 * 
 * @param info 单点信息结构，不能为NULL
 * @return 验证结果
 *         - 1: 单点信息有效
 *         - 0: 单点信息无效
 * 
 * @note 验证地址和品质描述词的有效性
 * @warning 输入指针不能为NULL
 * 
 * @see is_info_address_valid
 * @see is_siq_valid
 * @see single_point_info_t
 */
int validate_single_point_info(const single_point_info_t* info) {
    if (info == NULL) {
        return 0;
    }
    
    return (is_info_address_valid(info->info_addr) && is_siq_valid(info->siq));
}

/* ==================== 双点信息处理函数实现 ==================== */

/**
 * @brief 双点信息转换为字节数组
 * @details 将双点信息结构转换为104协议规定的字节数组格式。
 *          按照协议规范进行数据序列化。
 * 
 * @param info 双点信息结构，不能为NULL
 * @param buffer 输出缓冲区，不能为NULL
 * @param buffer_size 缓冲区大小
 * @param actual_length 实际写入长度输出，不能为NULL
 * @return 协议错误码
 *         - PROTOCOL_SUCCESS: 转换成功
 *         - PROTOCOL_ERROR_NULL_POINTER: 空指针错误
 *         - PROTOCOL_ERROR_BUFFER_TOO_SMALL: 缓冲区太小
 *         - PROTOCOL_ERROR_ASDU_INVALID_ADDRESS: 地址无效
 * 
 * @note 按照104协议规范进行数据序列化
 * @warning 缓冲区大小必须足够容纳转换后的数据
 * 
 * @see bytes_to_double_point_info
 * @see validate_double_point_info
 * @see buffer_write_u32
 * @see buffer_write_u8
 */
protocol_error_t double_point_info_to_bytes(const double_point_info_t* info,
                                           u8* buffer, u32 buffer_size, u32* actual_length) {
    LOG_DEBUG(LOG_MODULE_NAME, "转换双点信息到字节数组: info=%p, buffer=%p, buffer_size=%u", 
              info, buffer, buffer_size);
    
    if (info == NULL || buffer == NULL || actual_length == NULL) {
        LOG_ERROR(LOG_MODULE_NAME, "空指针参数错误");
        return PROTOCOL_ERROR_NULL_POINTER;
    }
    
    /* 验证双点信息 */
    LOG_DEBUG(LOG_MODULE_NAME, "验证信息对象地址: %u", info->info_addr);
    if (!is_info_address_valid(info->info_addr)) {
        LOG_ERROR(LOG_MODULE_NAME, "无效的信息对象地址: %u", info->info_addr);
        return PROTOCOL_ERROR_ASDU_INVALID_ADDRESS;
    }
    LOG_DEBUG(LOG_MODULE_NAME, "信息对象地址验证通过");
    
    LOG_DEBUG(LOG_MODULE_NAME, "验证双点信息品质");
    if (!is_diq_valid(*(uint8_t*)&info->diq)) {
        LOG_ERROR(LOG_MODULE_NAME, "无效的双点信息品质");
        return PROTOCOL_ERROR_DATA_INVALID_VALUE;
    }
    LOG_DEBUG(LOG_MODULE_NAME, "双点信息品质验证通过");
    
    /* 检查缓冲区大小 */
    if (buffer_size < 4) { /* 地址(3字节) + DIQ(1字节) */
        LOG_ERROR(LOG_MODULE_NAME, "缓冲区太小: %u < 4", buffer_size);
        return PROTOCOL_ERROR_BUFFER_TOO_SMALL;
    }
    LOG_DEBUG(LOG_MODULE_NAME, "缓冲区大小检查通过: %u >= 4", buffer_size);
    
    /* 写入信息对象地址 */
    LOG_DEBUG(LOG_MODULE_NAME, "写入信息对象地址: %u", info->info_addr);
    buffer_write_u32(buffer, 0, info->info_addr, 0);
    
    /* 写入DIQ */
    LOG_DEBUG(LOG_MODULE_NAME, "写入DIQ: 0x%02X 到缓冲区[3]", *(u8*)&info->diq);
    memcpy(&buffer[3], &info->diq, sizeof(diq_t));
    
    *actual_length = 4;
    LOG_INFO(LOG_MODULE_NAME, "双点信息成功转换为字节数组，实际长度: %u", *actual_length);
    return PROTOCOL_SUCCESS;
}

/**
 * @brief 字节数组转换为双点信息
 * @details 将104协议规定的字节数组格式转换为双点信息结构。
 *          按照协议规范进行数据反序列化。
 * 
 * @param data 字节数组，不能为NULL
 * @param length 数据长度
 * @param info 双点信息结构输出，不能为NULL
 * @return 协议错误码
 *         - PROTOCOL_SUCCESS: 转换成功
 *         - PROTOCOL_ERROR_NULL_POINTER: 空指针错误
 *         - PROTOCOL_ERROR_BUFFER_TOO_SMALL: 数据长度不足
 *         - PROTOCOL_ERROR_ASDU_INVALID_ADDRESS: 地址无效
 * 
 * @note 按照104协议规范进行数据反序列化
 * @warning 数据长度必须足够容纳双点信息
 * 
 * @see double_point_info_to_bytes
 * @see validate_double_point_info
 * @see buffer_read_u32
 * @see buffer_read_u8
 */
protocol_error_t bytes_to_double_point_info(const u8* data, u32 length,
                                           double_point_info_t* info) {
    LOG_DEBUG(LOG_MODULE_NAME, "从字节数组转换双点信息: data=%p, length=%u, info=%p", 
              data, length, info);
    
    if (data == NULL || info == NULL) {
        LOG_ERROR(LOG_MODULE_NAME, "空指针参数错误");
        return PROTOCOL_ERROR_NULL_POINTER;
    }
    
    /* 检查数据长度 */
    if (length < 4) { /* 地址(3字节) + DIQ(1字节) */
        LOG_ERROR(LOG_MODULE_NAME, "数据长度太小: %u < 4", length);
        return PROTOCOL_ERROR_BUFFER_TOO_SMALL;
    }
    LOG_DEBUG(LOG_MODULE_NAME, "数据长度检查通过: %u >= 4", length);
    
    /* 读取信息对象地址 */
    LOG_DEBUG(LOG_MODULE_NAME, "读取信息对象地址从缓冲区[0-2]");
    info->info_addr = buffer_read_u32(data, 0, NULL, 0);
    
    /* 读取DIQ */
    LOG_DEBUG(LOG_MODULE_NAME, "读取DIQ从缓冲区[3]");
    memcpy(&info->diq, &data[3], sizeof(diq_t));
    
    LOG_DEBUG(LOG_MODULE_NAME, "读取完成: 地址=%u, DIQ=0x%02X", 
              info->info_addr, *(u8*)&info->diq);
    
    /* 验证转换后的数据 */
    LOG_DEBUG(LOG_MODULE_NAME, "验证转换后的数据");
    if (!is_info_address_valid(info->info_addr)) {
        LOG_ERROR(LOG_MODULE_NAME, "信息对象地址无效: %u", info->info_addr);
        return PROTOCOL_ERROR_ASDU_INVALID_ADDRESS;
    }
    
    if (!is_diq_valid(*(uint8_t*)&info->diq)) {
        LOG_ERROR(LOG_MODULE_NAME, "DIQ无效: 0x%02X", *(u8*)&info->diq);
        return PROTOCOL_ERROR_DATA_INVALID_VALUE;
    }
    
    LOG_INFO(LOG_MODULE_NAME, "双点信息转换成功: 地址=%u, DIQ=0x%02X", 
             info->info_addr, *(u8*)&info->diq);
    return PROTOCOL_SUCCESS;
}

/**
 * @brief 验证双点信息
 * @details 验证双点信息结构的完整性和有效性。
 *          检查地址和品质描述词的有效性。
 * 
 * @param info 双点信息结构，不能为NULL
 * @return 验证结果
 *         - 1: 双点信息有效
 *         - 0: 双点信息无效
 * 
 * @note 验证地址和品质描述词的有效性
 * @warning 输入指针不能为NULL
 * 
 * @see is_info_address_valid
 * @see is_diq_valid
 * @see double_point_info_t
 */
int validate_double_point_info(const double_point_info_t* info) {
    LOG_DEBUG(LOG_MODULE_NAME, "验证双点信息: info=%p", info);
    
    if (info == NULL) {
        LOG_ERROR(LOG_MODULE_NAME, "空指针参数错误");
        return 0;
    }
    
    int valid = (is_info_address_valid(info->info_addr) && is_diq_valid(info->diq));
    LOG_INFO(LOG_MODULE_NAME, "双点信息验证结果: %s", valid ? "有效" : "无效");
    return valid;
}

/* ==================== 带时标的单点信息处理函数实现 ==================== */

/**
 * @brief 带时标的单点信息转换为字节数组
 * @details 将带时标的单点信息结构转换为104协议规定的字节数组格式。
 *          按照协议规范进行数据序列化，包含时间戳信息。
 * 
 * @param info 带时标的单点信息结构，不能为NULL
 * @param buffer 输出缓冲区，不能为NULL
 * @param buffer_size 缓冲区大小
 * @param actual_length 实际写入长度输出，不能为NULL
 * @return 协议错误码
 *         - PROTOCOL_SUCCESS: 转换成功
 *         - PROTOCOL_ERROR_NULL_POINTER: 空指针错误
 *         - PROTOCOL_ERROR_BUFFER_TOO_SMALL: 缓冲区太小
 *         - PROTOCOL_ERROR_ASDU_INVALID_ADDRESS: 地址无效
 *         - PROTOCOL_ERROR_DATA_INVALID_TIMESTAMP: 时间戳无效
 * 
 * @note 按照104协议规范进行数据序列化，包含时间戳
 * @warning 缓冲区大小必须足够容纳转换后的数据
 * 
 * @see bytes_to_single_point_info_with_time
 * @see validate_single_point_info_with_time
 * @see buffer_write_u32
 * @see buffer_write_u8
 * @see memcpy
 */
protocol_error_t single_point_info_with_time_to_bytes(const single_point_info_with_time_t* info,
                                                     u8* buffer, u32 buffer_size, u32* actual_length) {
    LOG_DEBUG(LOG_MODULE_NAME, "转换带时标的单点信息到字节数组: info=%p, buffer=%p, buffer_size=%u", 
              info, buffer, buffer_size);
    
    if (info == NULL || buffer == NULL || actual_length == NULL) {
        LOG_ERROR(LOG_MODULE_NAME, "空指针参数错误");
        return PROTOCOL_ERROR_NULL_POINTER;
    }
    
    /* 验证带时标的单点信息 */
    LOG_DEBUG(LOG_MODULE_NAME, "验证信息对象地址: %u", info->info_addr);
    if (!is_info_address_valid(info->info_addr)) {
        LOG_ERROR(LOG_MODULE_NAME, "无效的信息对象地址: %u", info->info_addr);
        return PROTOCOL_ERROR_ASDU_INVALID_ADDRESS;
    }
    LOG_DEBUG(LOG_MODULE_NAME, "信息对象地址验证通过");
    
    LOG_DEBUG(LOG_MODULE_NAME, "验证单点信息品质");
    if (!is_siq_valid(*(uint8_t*)&info->siq)) {
        LOG_ERROR(LOG_MODULE_NAME, "无效的单点信息品质");
        return PROTOCOL_ERROR_DATA_INVALID_VALUE;
    }
    LOG_DEBUG(LOG_MODULE_NAME, "单点信息品质验证通过");
    
    LOG_DEBUG(LOG_MODULE_NAME, "验证时间戳");
    if (!is_cp56time2a_valid(&info->time)) {
        LOG_ERROR(LOG_MODULE_NAME, "无效的时间戳");
        return PROTOCOL_ERROR_DATA_INVALID_TIMESTAMP;
    }
    LOG_DEBUG(LOG_MODULE_NAME, "时间戳验证通过");
    
    /* 检查缓冲区大小 */
    if (buffer_size < 11) { /* 地址(3字节) + SIQ(1字节) + 时间戳(7字节) */
        LOG_ERROR(LOG_MODULE_NAME, "缓冲区太小: %u < 11", buffer_size);
        return PROTOCOL_ERROR_BUFFER_TOO_SMALL;
    }
    LOG_DEBUG(LOG_MODULE_NAME, "缓冲区大小检查通过: %u >= 11", buffer_size);
    
    /* 写入信息对象地址 */
    LOG_DEBUG(LOG_MODULE_NAME, "写入信息对象地址: %u", info->info_addr);
    buffer_write_u32(buffer, 0, info->info_addr, 0);
    
    /* 写入SIQ */
    LOG_DEBUG(LOG_MODULE_NAME, "写入SIQ: 0x%02X 到缓冲区[3]", *(u8*)&info->siq);
    memcpy(&buffer[3], &info->siq, sizeof(siq_t));
    
    /* 写入时间戳 */
    LOG_DEBUG(LOG_MODULE_NAME, "写入时间戳到缓冲区[4-10]");
    memcpy(&buffer[4], &info->time, 7);
    
    *actual_length = 11;
    LOG_INFO(LOG_MODULE_NAME, "带时标的单点信息成功转换为字节数组，实际长度: %u", *actual_length);
    return PROTOCOL_SUCCESS;
}

/**
 * @brief 字节数组转换为带时标的单点信息
 * @details 将104协议规定的字节数组格式转换为带时标的单点信息结构。
 *          按照协议规范进行数据反序列化，包含时间戳信息。
 * 
 * @param data 字节数组，不能为NULL
 * @param length 数据长度
 * @param info 带时标的单点信息结构输出，不能为NULL
 * @return 协议错误码
 *         - PROTOCOL_SUCCESS: 转换成功
 *         - PROTOCOL_ERROR_NULL_POINTER: 空指针错误
 *         - PROTOCOL_ERROR_BUFFER_TOO_SMALL: 数据长度不足
 *         - PROTOCOL_ERROR_ASDU_INVALID_ADDRESS: 地址无效
 *         - PROTOCOL_ERROR_DATA_INVALID_TIMESTAMP: 时间戳无效
 * 
 * @note 按照104协议规范进行数据反序列化，包含时间戳
 * @warning 数据长度必须足够容纳带时标的单点信息
 * 
 * @see single_point_info_with_time_to_bytes
 * @see validate_single_point_info_with_time
 * @see buffer_read_u32
 * @see buffer_read_u8
 * @see memcpy
 */
protocol_error_t bytes_to_single_point_info_with_time(const u8* data, u32 length,
                                                     single_point_info_with_time_t* info) {
    LOG_DEBUG(LOG_MODULE_NAME, "从字节数组转换带时标的单点信息: data=%p, length=%u, info=%p", 
              data, length, info);
    
    if (data == NULL || info == NULL) {
        LOG_ERROR(LOG_MODULE_NAME, "空指针参数错误");
        return PROTOCOL_ERROR_NULL_POINTER;
    }
    
    /* 检查数据长度 */
    if (length < 11) { /* 地址(3字节) + SIQ(1字节) + 时间戳(7字节) */
        LOG_ERROR(LOG_MODULE_NAME, "数据长度太小: %u < 11", length);
        return PROTOCOL_ERROR_BUFFER_TOO_SMALL;
    }
    LOG_DEBUG(LOG_MODULE_NAME, "数据长度检查通过: %u >= 11", length);
    
    /* 读取信息对象地址 */
    LOG_DEBUG(LOG_MODULE_NAME, "读取信息对象地址从缓冲区[0-2]");
    info->info_addr = buffer_read_u32(data, 0, NULL, 0);
    
    /* 读取SIQ */
    LOG_DEBUG(LOG_MODULE_NAME, "读取SIQ从缓冲区[3]");
    memcpy(&info->siq, &data[3], sizeof(siq_t));
    
    /* 读取时间戳 */
    LOG_DEBUG(LOG_MODULE_NAME, "读取时间戳从缓冲区[4-10]");
    memcpy(&info->time, &data[4], 7);
    
    LOG_DEBUG(LOG_MODULE_NAME, "读取完成: 地址=%u, SIQ=0x%02X", 
              info->info_addr, *(u8*)&info->siq);
    
    /* 验证转换后的数据 */
    LOG_DEBUG(LOG_MODULE_NAME, "验证转换后的数据");
    if (!is_info_address_valid(info->info_addr)) {
        LOG_ERROR(LOG_MODULE_NAME, "信息对象地址无效: %u", info->info_addr);
        return PROTOCOL_ERROR_ASDU_INVALID_ADDRESS;
    }
    
    if (!is_siq_valid(*(uint8_t*)&info->siq)) {
        LOG_ERROR(LOG_MODULE_NAME, "SIQ无效: 0x%02X", *(u8*)&info->siq);
        return PROTOCOL_ERROR_DATA_INVALID_VALUE;
    }
    
    if (!is_cp56time2a_valid(&info->time)) {
        LOG_ERROR(LOG_MODULE_NAME, "时间戳无效");
        return PROTOCOL_ERROR_DATA_INVALID_TIMESTAMP;
    }
    
    LOG_INFO(LOG_MODULE_NAME, "带时标的单点信息转换成功: 地址=%u, SIQ=0x%02X", 
             info->info_addr, *(u8*)&info->siq);
    return PROTOCOL_SUCCESS;
}

/**
 * @brief 验证带时标的单点信息
 * @details 验证带时标的单点信息结构的完整性和有效性。
 *          检查地址、品质描述词和时间戳的有效性。
 * 
 * @param info 带时标的单点信息结构，不能为NULL
 * @return 验证结果
 *         - 1: 带时标的单点信息有效
 *         - 0: 带时标的单点信息无效
 * 
 * @note 验证地址、品质描述词和时间戳的有效性
 * @warning 输入指针不能为NULL
 * 
 * @see is_info_address_valid
 * @see is_siq_valid
 * @see is_cp56time2a_valid
 * @see single_point_info_with_time_t
 */
int validate_single_point_info_with_time(const single_point_info_with_time_t* info) {
    LOG_DEBUG(LOG_MODULE_NAME, "验证带时标的单点信息: info=%p", info);
    
    if (info == NULL) {
        LOG_ERROR(LOG_MODULE_NAME, "空指针参数错误");
        return 0;
    }
    
    int valid = (is_info_address_valid(info->info_addr) && 
                  is_siq_valid(*(uint8_t*)&info->siq) &&
                 is_cp56time2a_valid(&info->time));
    LOG_INFO(LOG_MODULE_NAME, "带时标的单点信息验证结果: %s", valid ? "有效" : "无效");
    return valid;
}

/* ==================== 带时标的双点信息处理函数实现 ==================== */

/**
 * @brief 带时标的双点信息转换为字节数组
 * @details 将带时标的双点信息结构转换为104协议规定的字节数组格式。
 *          按照协议规范进行数据序列化，包含时间戳信息。
 * 
 * @param info 带时标的双点信息结构，不能为NULL
 * @param buffer 输出缓冲区，不能为NULL
 * @param buffer_size 缓冲区大小
 * @param actual_length 实际写入长度输出，不能为NULL
 * @return 协议错误码
 *         - PROTOCOL_SUCCESS: 转换成功
 *         - PROTOCOL_ERROR_NULL_POINTER: 空指针错误
 *         - PROTOCOL_ERROR_BUFFER_TOO_SMALL: 缓冲区太小
 *         - PROTOCOL_ERROR_ASDU_INVALID_ADDRESS: 地址无效
 *         - PROTOCOL_ERROR_DATA_INVALID_TIMESTAMP: 时间戳无效
 * 
 * @note 按照104协议规范进行数据序列化，包含时间戳
 * @warning 缓冲区大小必须足够容纳转换后的数据
 * 
 * @see bytes_to_double_point_info_with_time
 * @see validate_double_point_info_with_time
 * @see buffer_write_u32
 * @see buffer_write_u8
 * @see memcpy
 */
protocol_error_t double_point_info_with_time_to_bytes(const double_point_info_with_time_t* info,
                                                     u8* buffer, u32 buffer_size, u32* actual_length) {
    LOG_DEBUG(LOG_MODULE_NAME, "转换带时标的双点信息到字节数组: info=%p, buffer=%p, buffer_size=%u", 
              info, buffer, buffer_size);
    
    if (info == NULL || buffer == NULL || actual_length == NULL) {
        LOG_ERROR(LOG_MODULE_NAME, "空指针参数错误");
        return PROTOCOL_ERROR_NULL_POINTER;
    }
    
    /* 验证带时标的双点信息 */
    LOG_DEBUG(LOG_MODULE_NAME, "验证信息对象地址: %u", info->info_addr);
    if (!is_info_address_valid(info->info_addr)) {
        LOG_ERROR(LOG_MODULE_NAME, "无效的信息对象地址: %u", info->info_addr);
        return PROTOCOL_ERROR_ASDU_INVALID_ADDRESS;
    }
    LOG_DEBUG(LOG_MODULE_NAME, "信息对象地址验证通过");
    
    LOG_DEBUG(LOG_MODULE_NAME, "验证双点信息品质");
    if (!is_diq_valid(*(uint8_t*)&info->diq)) {
        LOG_ERROR(LOG_MODULE_NAME, "无效的双点信息品质");
        return PROTOCOL_ERROR_DATA_INVALID_VALUE;
    }
    LOG_DEBUG(LOG_MODULE_NAME, "双点信息品质验证通过");
    
    LOG_DEBUG(LOG_MODULE_NAME, "验证时间戳");
    if (!is_cp56time2a_valid(&info->time)) {
        LOG_ERROR(LOG_MODULE_NAME, "无效的时间戳");
        return PROTOCOL_ERROR_DATA_INVALID_TIMESTAMP;
    }
    LOG_DEBUG(LOG_MODULE_NAME, "时间戳验证通过");
    
    /* 检查缓冲区大小 */
    if (buffer_size < 11) { /* 地址(3字节) + DIQ(1字节) + 时间戳(7字节) */
        LOG_ERROR(LOG_MODULE_NAME, "缓冲区太小: %u < 11", buffer_size);
        return PROTOCOL_ERROR_BUFFER_TOO_SMALL;
    }
    LOG_DEBUG(LOG_MODULE_NAME, "缓冲区大小检查通过: %u >= 11", buffer_size);
    
    /* 写入信息对象地址 */
    LOG_DEBUG(LOG_MODULE_NAME, "写入信息对象地址: %u", info->info_addr);
    buffer_write_u32(buffer, 0, info->info_addr, 0);
    
    /* 写入DIQ */
    LOG_DEBUG(LOG_MODULE_NAME, "写入DIQ: 0x%02X 到缓冲区[3]", *(u8*)&info->diq);
    memcpy(&buffer[3], &info->diq, sizeof(diq_t));
    
    /* 写入时间戳 */
    LOG_DEBUG(LOG_MODULE_NAME, "写入时间戳到缓冲区[4-10]");
    memcpy(&buffer[4], &info->time, 7);
    
    *actual_length = 11;
    LOG_INFO(LOG_MODULE_NAME, "带时标的双点信息成功转换为字节数组，实际长度: %u", *actual_length);
    return PROTOCOL_SUCCESS;
}

/**
 * @brief 字节数组转换为带时标的双点信息
 * @details 将104协议规定的字节数组格式转换为带时标的双点信息结构。
 *          按照协议规范进行数据反序列化，包含时间戳信息。
 * 
 * @param data 字节数组，不能为NULL
 * @param length 数据长度
 * @param info 带时标的双点信息结构输出，不能为NULL
 * @return 协议错误码
 *         - PROTOCOL_SUCCESS: 转换成功
 *         - PROTOCOL_ERROR_NULL_POINTER: 空指针错误
 *         - PROTOCOL_ERROR_BUFFER_TOO_SMALL: 数据长度不足
 *         - PROTOCOL_ERROR_ASDU_INVALID_ADDRESS: 地址无效
 *         - PROTOCOL_ERROR_DATA_INVALID_TIMESTAMP: 时间戳无效
 * 
 * @note 按照104协议规范进行数据反序列化，包含时间戳
 * @warning 数据长度必须足够容纳带时标的双点信息
 * 
 * @see double_point_info_with_time_to_bytes
 * @see validate_double_point_info_with_time
 * @see buffer_read_u32
 * @see buffer_read_u8
 * @see memcpy
 */
protocol_error_t bytes_to_double_point_info_with_time(const u8* data, u32 length,
                                                     double_point_info_with_time_t* info) {
    LOG_DEBUG(LOG_MODULE_NAME, "从字节数组转换带时标的双点信息: data=%p, length=%u, info=%p", 
              data, length, info);
    
    if (data == NULL || info == NULL) {
        LOG_ERROR(LOG_MODULE_NAME, "空指针参数错误");
        return PROTOCOL_ERROR_NULL_POINTER;
    }
    
    /* 检查数据长度 */
    if (length < 11) { /* 地址(3字节) + DIQ(1字节) + 时间戳(7字节) */
        LOG_ERROR(LOG_MODULE_NAME, "数据长度太小: %u < 11", length);
        return PROTOCOL_ERROR_BUFFER_TOO_SMALL;
    }
    LOG_DEBUG(LOG_MODULE_NAME, "数据长度检查通过: %u >= 11", length);
    
    /* 读取信息对象地址 */
    LOG_DEBUG(LOG_MODULE_NAME, "读取信息对象地址从缓冲区[0-2]");
    info->info_addr = buffer_read_u32(data, 0, NULL, 0);
    
    /* 读取DIQ */
    LOG_DEBUG(LOG_MODULE_NAME, "读取DIQ从缓冲区[3]");
    memcpy(&info->diq, &data[3], sizeof(diq_t));
    
    /* 读取时间戳 */
    LOG_DEBUG(LOG_MODULE_NAME, "读取时间戳从缓冲区[4-10]");
    memcpy(&info->time, &data[4], 7);
    
    LOG_DEBUG(LOG_MODULE_NAME, "读取完成: 地址=%u, DIQ=0x%02X", 
              info->info_addr, *(u8*)&info->diq);
    
    /* 验证转换后的数据 */
    LOG_DEBUG(LOG_MODULE_NAME, "验证转换后的数据");
    if (!is_info_address_valid(info->info_addr)) {
        LOG_ERROR(LOG_MODULE_NAME, "信息对象地址无效: %u", info->info_addr);
        return PROTOCOL_ERROR_ASDU_INVALID_ADDRESS;
    }
    
    if (!is_diq_valid(*(uint8_t*)&info->diq)) {
        LOG_ERROR(LOG_MODULE_NAME, "DIQ无效: 0x%02X", *(u8*)&info->diq);
        return PROTOCOL_ERROR_DATA_INVALID_VALUE;
    }
    
    if (!is_cp56time2a_valid(&info->time)) {
        LOG_ERROR(LOG_MODULE_NAME, "时间戳无效");
        return PROTOCOL_ERROR_DATA_INVALID_TIMESTAMP;
    }
    
    LOG_INFO(LOG_MODULE_NAME, "带时标的双点信息转换成功: 地址=%u, DIQ=0x%02X", 
             info->info_addr, *(u8*)&info->diq);
    return PROTOCOL_SUCCESS;
}

/**
 * @brief 验证带时标的双点信息
 * @details 验证带时标的双点信息结构的完整性和有效性。
 *          检查地址、品质描述词和时间戳的有效性。
 * 
 * @param info 带时标的双点信息结构，不能为NULL
 * @return 验证结果
 *         - 1: 带时标的双点信息有效
 *         - 0: 带时标的双点信息无效
 * 
 * @note 验证地址、品质描述词和时间戳的有效性
 * @warning 输入指针不能为NULL
 * 
 * @see is_info_address_valid
 * @see is_diq_valid
 * @see is_cp56time2a_valid
 * @see double_point_info_with_time_t
 */
int validate_double_point_info_with_time(const double_point_info_with_time_t* info) {
    LOG_DEBUG(LOG_MODULE_NAME, "验证带时标的双点信息: info=%p", info);
    
    if (info == NULL) {
        LOG_ERROR(LOG_MODULE_NAME, "空指针参数错误");
        return 0;
    }
    
    int valid = (is_info_address_valid(info->info_addr) && 
                  is_diq_valid(*(uint8_t*)&info->diq) &&
                 is_cp56time2a_valid(&info->time));
    LOG_INFO(LOG_MODULE_NAME, "带时标的双点信息验证结果: %s", valid ? "有效" : "无效");
    return valid;
}

/* ==================== 故障事件信息处理函数实现 ==================== */

/**
 * @brief 故障事件信息转换为字节数组
 * @details 将故障事件信息结构转换为104协议规定的字节数组格式。
 *          按照协议规范进行数据序列化，包含故障类型、状态和时间戳信息。
 * 
 * @param fault_info 故障事件信息结构，不能为NULL
 * @param buffer 输出缓冲区，不能为NULL
 * @param buffer_size 缓冲区大小
 * @param actual_length 实际写入长度输出，不能为NULL
 * @return 协议错误码
 *         - PROTOCOL_SUCCESS: 转换成功
 *         - PROTOCOL_ERROR_NULL_POINTER: 空指针错误
 *         - PROTOCOL_ERROR_BUFFER_TOO_SMALL: 缓冲区太小
 *         - PROTOCOL_ERROR_ASDU_INVALID_ADDRESS: 地址无效
 *         - PROTOCOL_ERROR_DATA_INVALID_TIMESTAMP: 时间戳无效
 * 
 * @note 按照104协议规范进行数据序列化，包含故障信息
 * @warning 缓冲区大小必须足够容纳转换后的数据
 * 
 * @see bytes_to_fault_event_info
 * @see validate_fault_event_info
 * @see buffer_write_u32
 * @see buffer_write_u8
 * @see memcpy
 */
protocol_error_t fault_event_info_to_bytes(const fault_event_info_t* fault_info,
                                          u8* buffer, u32 buffer_size, u32* actual_length) {
    LOG_DEBUG(LOG_MODULE_NAME, "转换故障事件信息到字节数组: fault_info=%p, buffer=%p, buffer_size=%u", 
              fault_info, buffer, buffer_size);
    
    if (fault_info == NULL || buffer == NULL || actual_length == NULL) {
        LOG_ERROR(LOG_MODULE_NAME, "空指针参数错误");
        return PROTOCOL_ERROR_NULL_POINTER;
    }
    
    /* 验证故障事件信息 */
    LOG_DEBUG(LOG_MODULE_NAME, "验证故障遥信点号: %u", fault_info->di_addr);
    if (!is_info_address_valid(fault_info->di_addr)) {
        LOG_ERROR(LOG_MODULE_NAME, "无效的故障遥信点号: %u", fault_info->di_addr);
        return PROTOCOL_ERROR_ASDU_INVALID_ADDRESS;
    }
    LOG_DEBUG(LOG_MODULE_NAME, "故障遥信点号验证通过");
    
    LOG_DEBUG(LOG_MODULE_NAME, "验证故障时刻时标");
    if (!is_cp56time2a_valid(&fault_info->fault_time)) {
        LOG_ERROR(LOG_MODULE_NAME, "无效的故障时刻时标");
        return PROTOCOL_ERROR_DATA_INVALID_TIMESTAMP;
    }
    LOG_DEBUG(LOG_MODULE_NAME, "故障时刻时标验证通过");
    
    /* 检查缓冲区大小 */
    if (buffer_size < 12) { /* 地址(3字节) + 故障类型(1字节) + 故障状态(1字节) + 时间戳(7字节) */
        LOG_ERROR(LOG_MODULE_NAME, "缓冲区太小: %u < 12", buffer_size);
        return PROTOCOL_ERROR_BUFFER_TOO_SMALL;
    }
    LOG_DEBUG(LOG_MODULE_NAME, "缓冲区大小检查通过: %u >= 12", buffer_size);
    
    /* 写入信息对象地址 */
    LOG_DEBUG(LOG_MODULE_NAME, "写入故障遥信点号: %u", fault_info->di_addr);
    buffer_write_u32(buffer, 0, fault_info->di_addr, 0);
    
    /* 写入故障类型 */
    LOG_DEBUG(LOG_MODULE_NAME, "写入故障类型: %u 到缓冲区[3]", fault_info->di_type);
    buffer[3] = fault_info->di_type;
    
    /* 写入故障状态 */
    LOG_DEBUG(LOG_MODULE_NAME, "写入故障状态: %u 到缓冲区[4]", fault_info->di_value);
    buffer[4] = fault_info->di_value;
    
    /* 写入时间戳 */
    LOG_DEBUG(LOG_MODULE_NAME, "写入故障时刻时标到缓冲区[5-11]");
    memcpy((void*)&fault_info->fault_time, &buffer[5], 7);
    
    *actual_length = 12;
    LOG_INFO(LOG_MODULE_NAME, "故障事件信息成功转换为字节数组，实际长度: %u", *actual_length);
    return PROTOCOL_SUCCESS;
}

/**
 * @brief 字节数组转换为故障事件信息
 * @details 将104协议规定的字节数组格式转换为故障事件信息结构。
 *          按照协议规范进行数据反序列化，包含故障类型、状态和时间戳信息。
 * 
 * @param data 字节数组，不能为NULL
 * @param length 数据长度
 * @param fault_info 故障事件信息结构输出，不能为NULL
 * @return 协议错误码
 *         - PROTOCOL_SUCCESS: 转换成功
 *         - PROTOCOL_ERROR_NULL_POINTER: 空指针错误
 *         - PROTOCOL_ERROR_BUFFER_TOO_SMALL: 数据长度不足
 *         - PROTOCOL_ERROR_ASDU_INVALID_ADDRESS: 地址无效
 *         - PROTOCOL_ERROR_DATA_INVALID_TIMESTAMP: 时间戳无效
 * 
 * @note 按照104协议规范进行数据反序列化，包含故障信息
 * @warning 数据长度必须足够容纳故障事件信息
 * 
 * @see fault_event_info_to_bytes
 * @see validate_fault_event_info
 * @see buffer_read_u32
 * @see buffer_read_u8
 * @see memcpy
 */
protocol_error_t bytes_to_fault_event_info(const u8* data, u32 length,
                                          fault_event_info_t* fault_info) {
    LOG_DEBUG(LOG_MODULE_NAME, "从字节数组转换故障事件信息: data=%p, length=%u, fault_info=%p", 
              data, length, fault_info);
    
    if (data == NULL || fault_info == NULL) {
        LOG_ERROR(LOG_MODULE_NAME, "空指针参数错误");
        return PROTOCOL_ERROR_NULL_POINTER;
    }
    
    /* 检查数据长度 */
    if (length < 12) { /* 地址(3字节) + 故障类型(1字节) + 故障状态(1字节) + 时间戳(7字节) */
        LOG_ERROR(LOG_MODULE_NAME, "数据长度太小: %u < 12", length);
        return PROTOCOL_ERROR_BUFFER_TOO_SMALL;
    }
    LOG_DEBUG(LOG_MODULE_NAME, "数据长度检查通过: %u >= 12", length);
    
    /* 读取信息对象地址 */
    LOG_DEBUG(LOG_MODULE_NAME, "读取故障遥信点号从缓冲区[0-2]");
    fault_info->di_addr = buffer_read_u32(data, 0, NULL, 0);
    
    /* 读取故障类型 */
    LOG_DEBUG(LOG_MODULE_NAME, "读取故障类型从缓冲区[3]");
    fault_info->di_type = data[3];
    
    /* 读取故障状态 */
    LOG_DEBUG(LOG_MODULE_NAME, "读取故障状态从缓冲区[4]");
    fault_info->di_value = data[4];
    
    /* 读取时间戳 */
    LOG_DEBUG(LOG_MODULE_NAME, "读取故障时刻时标从缓冲区[5-11]");
    memcpy(&fault_info->fault_time, &data[5], 7);
    
    LOG_DEBUG(LOG_MODULE_NAME, "读取完成: 故障遥信点号=%u, 故障类型=%u, 故障状态=%u", 
              fault_info->di_addr, fault_info->di_type, fault_info->di_value);
    
    /* 验证转换后的数据 */
    LOG_DEBUG(LOG_MODULE_NAME, "验证转换后的数据");
    if (!is_info_address_valid(fault_info->di_addr)) {
        LOG_ERROR(LOG_MODULE_NAME, "故障遥信点号无效: %u", fault_info->di_addr);
        return PROTOCOL_ERROR_ASDU_INVALID_ADDRESS;
    }
    
    if (!is_cp56time2a_valid(&fault_info->fault_time)) {
        LOG_ERROR(LOG_MODULE_NAME, "故障时刻时标无效");
        return PROTOCOL_ERROR_DATA_INVALID_TIMESTAMP;
    }
    
    LOG_INFO(LOG_MODULE_NAME, "故障事件信息转换成功: 故障遥信点号=%u, 故障类型=%u, 故障状态=%u", 
             fault_info->di_addr, fault_info->di_type, fault_info->di_value);
    return PROTOCOL_SUCCESS;
}

/**
 * @brief 验证故障事件信息
 * @details 验证故障事件信息结构的完整性和有效性。
 *          检查地址、故障类型、故障状态和时间戳的有效性。
 * 
 * @param fault_info 故障事件信息结构，不能为NULL
 * @return 验证结果
 *         - 1: 故障事件信息有效
 *         - 0: 故障事件信息无效
 * 
 * @note 验证地址、故障类型、故障状态和时间戳的有效性
 * @warning 输入指针不能为NULL
 * 
 * @see is_info_address_valid
 * @see is_cp56time2a_valid
 * @see fault_event_info_t
 */
int validate_fault_event_info(const fault_event_info_t* fault_info) {
    LOG_DEBUG(LOG_MODULE_NAME, "验证故障事件信息: fault_info=%p", fault_info);
    
    if (fault_info == NULL) {
        LOG_ERROR(LOG_MODULE_NAME, "空指针参数错误");
        return 0;
    }
    
    int valid = (is_info_address_valid(fault_info->di_addr) && 
                 is_cp56time2a_valid(&fault_info->fault_time));
    LOG_INFO(LOG_MODULE_NAME, "故障事件信息验证结果: %s", valid ? "有效" : "无效");
    return valid;
}

/* ==================== 辅助函数实现 ==================== */

/**
 * @brief 获取单点信息大小
 * @details 获取单点信息结构在字节数组中的大小。
 *          用于缓冲区大小计算。
 * 
 * @return 单点信息大小（字节）
 * 
 * @note 单点信息大小：4字节（地址3字节 + SIQ1字节）
 * @warning 此函数是线程安全的
 * 
 * @see get_double_point_info_size
 * @see get_single_point_info_with_time_size
 * @see single_point_info_t
 */
u32 get_single_point_info_size(void) {
    LOG_DEBUG(LOG_MODULE_NAME, "获取单点信息大小");
    u32 size = 4; /* 地址(3字节) + SIQ(1字节) */
    LOG_INFO(LOG_MODULE_NAME, "单点信息大小: %u字节", size);
    return size;
}

/**
 * @brief 获取双点信息大小
 * @details 获取双点信息结构在字节数组中的大小。
 *          用于缓冲区大小计算。
 * 
 * @return 双点信息大小（字节）
 * 
 * @note 双点信息大小：4字节（地址3字节 + DIQ1字节）
 * @warning 此函数是线程安全的
 * 
 * @see get_single_point_info_size
 * @see get_double_point_info_with_time_size
 * @see double_point_info_t
 */
u32 get_double_point_info_size(void) {
    LOG_DEBUG(LOG_MODULE_NAME, "获取双点信息大小");
    u32 size = 4; /* 地址(3字节) + DIQ(1字节) */
    LOG_INFO(LOG_MODULE_NAME, "双点信息大小: %u字节", size);
    return size;
}

/**
 * @brief 获取带时标的单点信息大小
 * @details 获取带时标的单点信息结构在字节数组中的大小。
 *          用于缓冲区大小计算。
 * 
 * @return 带时标的单点信息大小（字节）
 * 
 * @note 带时标的单点信息大小：11字节（地址3字节 + SIQ1字节 + 时间戳7字节）
 * @warning 此函数是线程安全的
 * 
 * @see get_single_point_info_size
 * @see get_double_point_info_with_time_size
 * @see single_point_info_with_time_t
 */
u32 get_single_point_info_with_time_size(void) {
    LOG_DEBUG(LOG_MODULE_NAME, "获取带时标的单点信息大小");
    u32 size = 11; /* 地址(3字节) + SIQ(1字节) + 时间戳(7字节) */
    LOG_INFO(LOG_MODULE_NAME, "带时标的单点信息大小: %u字节", size);
    return size;
}

/**
 * @brief 获取带时标的双点信息大小
 * @details 获取带时标的双点信息结构在字节数组中的大小。
 *          用于缓冲区大小计算。
 * 
 * @return 带时标的双点信息大小（字节）
 * 
 * @note 带时标的双点信息大小：11字节（地址3字节 + DIQ1字节 + 时间戳7字节）
 * @warning 此函数是线程安全的
 * 
 * @see get_double_point_info_size
 * @see get_single_point_info_with_time_size
 * @see double_point_info_with_time_t
 */
u32 get_double_point_info_with_time_size(void) {
    LOG_DEBUG(LOG_MODULE_NAME, "获取带时标的双点信息大小");
    u32 size = 11; /* 地址(3字节) + DIQ(1字节) + 时间戳(7字节) */
    LOG_INFO(LOG_MODULE_NAME, "带时标的双点信息大小: %u字节", size);
    return size;
}

/**
 * @brief 获取故障事件信息大小
 * @details 获取故障事件信息结构在字节数组中的大小。
 *          用于缓冲区大小计算。
 * 
 * @return 故障事件信息大小（字节）
 * 
 * @note 故障事件信息大小：12字节（地址3字节 + 故障类型1字节 + 故障状态1字节 + 时间戳7字节）
 * @warning 此函数是线程安全的
 * 
 * @see get_single_point_info_with_time_size
 * @see get_double_point_info_with_time_size
 * @see fault_event_info_t
 */
u32 get_fault_event_info_size(void) {
    LOG_DEBUG(LOG_MODULE_NAME, "获取故障事件信息大小");
    u32 size = 12; /* 地址(3字节) + 故障类型(1字节) + 故障状态(1字节) + 时间戳(7字节) */
    LOG_INFO(LOG_MODULE_NAME, "故障事件信息大小: %u字节", size);
    return size;
}
